package com.md.api.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.md.api.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;

/**
 * execl导出工具类
 *
 * @author chenxu
 */
@Slf4j
@Component
public class ExeclUploadUtils {


    // 缺省值
    private static final String DEFAULT_VALUE = "-";
    private static final String BUCKET_NAME = "dsk-oss";

    private static final String filePathPropertisName = "excel.file.root.path";


    @Autowired
    AliOssUtil aliOssUtil;


    /**
     * 导出
     * @param url   回调地址
     * @param unicode   订单唯一码
     * @param path  文件地址
     */
    public void exportFileRelate(String url,String unicode,String path)  {
        try {
            JSONObject json = new JSONObject();
            json.put("url",path);
            json.put("uniqueCode",unicode);
            String s = HttpClientUtils.postJson(url, json);
            log.info("回调地址返回："+s);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException("导出回调失败！");
        }
    }


    /**
     * 批量导出
     * @param url   回调地址
     * @param unicode   订单唯一码
     * @param path  文件地址
     */
    public void batchExportFileRelate(String url,String unicode,String path,long dataCount)  {
        try {
            JSONObject json = new JSONObject();
            json.put("url",path);
            json.put("count",dataCount);
            json.put("uniqueCode",unicode);
            String s = HttpClientUtils.postJson(url, json);
            log.info("回调地址返回："+s);
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException("导出回调失败！");
        }
    }

    /**
     * 导出execlXSSFSheet
     *
     * @param rawExeclName    原execl名称
     * @param list            数据结果集
     * @param exportExeclName 导出execl名称
     * @param startRowIndex   数据从startRowIndex下标行开始写 0表示从第一行开始写
     * @param merge           相同数据是否合并
     * @param rules           导出列规则 支持四种形式
     *                        1.String 字段名称
     *                        2.Function<?,String>
     *                        3.new ExeclExportUtils.RowConvert<?>()
     *                        4.new ExeclExportUtils.ListConvert<?>()
     * @throws Exception
     */
    public  <T> void exportExcel(HttpServletResponse response,String filePath, String rawExeclName, List<T> list,
                                       String exportExeclName, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, String redField, String keyword, Object... rules) throws Exception {
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setHeader("Content-Disposition", new StringBuilder("attachment;filename=")
                .append(URLEncoder.encode(exportExeclName, "utf-8")).toString());
        XSSFWorkbook wb = generate(filePath, rawExeclName, list, startRowIndex, merge, isHighLightKeyword, redField, keyword, rules);
        try {
            wb.write(response.getOutputStream());
        } finally {
//			wb.close();
        }
    }

//    public  <T> QiniuPutRet uploadExcel(HttpServletResponse response,String filePath, String rawExeclName, List<T> list,
//                                 String exportExeclName, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, String redField, String keyword, Object... rules) throws Exception {
//        XSSFWorkbook wb = generate(filePath, rawExeclName, list, startRowIndex, merge, isHighLightKeyword, redField, keyword, rules);
//        try {
//            return qiniuUtil.uploadToQiniu(wb,exportExeclName);
//        } finally {
////			wb.close();
//        }
//    }

    public  <T> String uploadExcelOss(HttpServletResponse response,String filePath, String rawExeclName, List<T> list, String dir,
                                        String exportExeclName, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, String redField, String keyword, Object... rules) throws Exception {
        long start = System.currentTimeMillis();
        XSSFWorkbook wb = generate(filePath, rawExeclName, list, startRowIndex, merge, isHighLightKeyword, redField, keyword, rules);
        try {
            long end = System.currentTimeMillis();
            log.info("数据导出表格生成耗时："+ (end - start) + " ms");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                wb.write(bos);
            } catch (IOException e) {
            } finally {
                try {
                    bos.close();
                } catch (IOException e) {
                }
            }
            byte[] brray = bos.toByteArray();
            InputStream is = new ByteArrayInputStream(brray);
            String path = AliOssUtil.uploadExcel(is, dir, exportExeclName);
            long endupload = System.currentTimeMillis();
            log.info("数据导出表格上传耗时："+ (endupload - end) + " ms");
            return path;
        } finally {
//			wb.close();
        }
    }

//    @Async
//    public  <T> void uploadExcelAsync(HttpServletResponse response,String filePath, String rawExeclName, List<T> list,
//                                 String exportExeclName, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, String redField, String keyword, Object... rules) throws Exception {
//        XSSFWorkbook wb = generate(filePath, rawExeclName, list, startRowIndex, merge, isHighLightKeyword, redField, keyword, rules);
//        try {
//            qiniuUtil.uploadToQiniu(wb,exportExeclName);
//        } finally {
////			wb.close();
//        }
//    }

    private static  <T> XSSFWorkbook generate(String filePath, String rawExeclName,List<T> list, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, String field, String keywords, Object... rules)
            throws Exception {
        File file = new File(filePath + File.separator + rawExeclName);
        FileInputStream is = new FileInputStream(file);
        XSSFWorkbook wb = new XSSFWorkbook(is);
        XSSFSheet sheet = wb.getSheetAt(0);
        Font font = wb.createFont();
        //开始加上水印
//        BufferedImage image = FontImage.drawText("./jiansheku.png", 500,1000);
//        ByteArrayOutputStream os = new ByteArrayOutputStream();
//        ImageIO.write(image, "png", os);
//        int pictureIdx = wb.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
//        POIXMLDocumentPart poixmlDocumentPart = wb.getAllPictures().get(pictureIdx);
//        PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
//        String relType = XSSFRelation.IMAGES.getRelation();
//        PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
//        sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        //结束水印
        write(list, sheet, startRowIndex, merge, isHighLightKeyword, font, field, keywords, rules);
        return wb;
    }


    private static <T> void write(List<T> list, XSSFSheet sheet, Integer startRowIndex, boolean merge, Boolean isHighLightKeyword, Font font, String field, String keywords, Object... rules) {
        String firstRowKey = "row_first";
        String endRowKey = "row_end";
        String firstCell = "cell_first";
        String endCell = "cell_end";
        Map<String, Map<String, Integer>> rowValIndex = new HashMap<String, Map<String, Integer>>();
        Map<String, Map<String, Integer>> cellValIndex = new HashMap<String, Map<String, Integer>>();
        for (int i = 0; i < list.size(); i++) {
            XSSFRow row = sheet.createRow(i + startRowIndex);
            T obj = list.get(i);
            for (int j = 0; j < rules.length; j++) {
                String val = getValue(list, obj, rules[j], i);
                Map<String, Integer> rows = new HashMap<String, Integer>();
                rows.put(firstRowKey, i + startRowIndex);
                rowValIndex.put(val, rows);
                rowValIndex.get(val).put(endRowKey, i + startRowIndex);
                Map<String, Integer> cells = new HashMap<String, Integer>();
                cells.put(firstCell, j);
                cellValIndex.put(val, cells);
                cellValIndex.get(val).put(endCell, j);
                String lowerValue = val.toLowerCase();
                XSSFRichTextString ts = new XSSFRichTextString(val); //单元格内容
                font.setFontName("微软雅黑"); // 字体
                font.setFontHeightInPoints((short) 10);
                font.setColor(HSSFColor.BLACK.index);  //颜色
                try {
                    ts.applyFont(font);
                }catch (Exception e){
                    e.printStackTrace();
                }
                row.createCell(j).setCellValue(ts);
                if (!val.equals("-") && (rules[j].toString().equalsIgnoreCase("licenceMoney") ||
                        rules[j].toString().equalsIgnoreCase("contractMoney") ||
                        rules[j].toString().equalsIgnoreCase("tenderMoney") ||
                        rules[j].toString().equalsIgnoreCase("completionMoney"))) {
                    font.setColor(HSSFColor.RED.index);  //颜色
                    List<String> moenyList = Arrays.asList(val.split("\\|"));
                    for (String s : moenyList) {
                        int indexOf = lowerValue.indexOf(s.toLowerCase());
                        Double moeny = Double.valueOf(s);
                        if (indexOf >= 0 && moeny > 1000000) {
                            ts.applyFont(indexOf, indexOf + s.length(), font);
                        }
                    }
                    row.getCell(j).setCellValue(ts);
                    continue;
                }
                //关键词高亮
                if (null != isHighLightKeyword && isHighLightKeyword && StringUtils.isNotEmpty(keywords) && field.contains(rules[j].toString())) {
                    List<String> keywordList = StringUtils.toListSpace(keywords);
                    font.setColor(HSSFColor.RED.index);  //颜色
                    for (String s : keywordList) {
                        List<Integer> allIndex = StringUtils.getAllIndex(lowerValue, s.toLowerCase());
                        if (!CollectionUtils.isEmpty(allIndex)) {
                            for (Integer t : allIndex) {
                                try {
                                    ts.applyFont(t, t + s.length(), font);
                                }catch (Exception e){
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                    row.getCell(j).setCellValue(ts);
                    continue;
                }
            }
        }
        if (merge) {
            for (Entry<String, Map<String, Integer>> data : rowValIndex.entrySet()) {
                int startRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(firstRowKey), 0).toString());
                int endRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(endRowKey), 0).toString());
                int startCell = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(firstCell)) {
                    startCell = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(firstCell), 0).toString());
                }
                int endCellIndex = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(endCell)) {
                    endCellIndex = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(endCell), 0).toString());
                }
                if (endRow < startRow) {
                    continue;
                }
//				log.info("key:"+data.getKey()+"-----------value:"+data.getValue().toString());
//				log.info("导出----》：startRow="+startRow+",endRow="+endRow+",startCell="+startCell+",endCellIndex="+endCellIndex);
                sheet.addMergedRegion(new CellRangeAddress(
                        startRow, //first row (0-based)
                        endRow, //last row  (0-based)
                        startCell, //first column (0-based)
                        endCellIndex  //last column  (0-based)
                ));
            }
        }
    }


    public static <T> void writeSheet(List<T> list, XSSFSheet sheet, Integer startRowIndex, boolean merge, List<String> rules, Boolean isHighLightKeyword, Font font, String keyword, Set<String> keyStrSet) {
        String firstRowKey = "row_first";
        String endRowKey = "row_end";
        String firstCell = "cell_first";
        String endCell = "cell_end";
        Map<String, Map<String, Integer>> rowValIndex = new HashMap<String, Map<String, Integer>>();

        Map<String, Map<String, Integer>> cellValIndex = new HashMap<String, Map<String, Integer>>();
        for (int i = 0; i < list.size(); i++) {
            XSSFRow row = sheet.createRow(i + startRowIndex);
            T obj = list.get(i);
            for (int j = 0; j < rules.size(); j++) {
                String val = getValue(list, obj, rules.get(j), i);
                Map<String, Integer> rows = new HashMap<String, Integer>();
                rows.put(firstRowKey, i + startRowIndex);
                rowValIndex.put(val, rows);
                rowValIndex.get(val).put(endRowKey, i + startRowIndex);
                Map<String, Integer> cells = new HashMap<String, Integer>();
                cells.put(firstCell, j);
                cellValIndex.put(val, cells);
                cellValIndex.get(val).put(endCell, j);
                //关键词高亮
                font.setFontName("宋体"); // 字体
                font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);//粗体显示
                font.setColor(HSSFColor.RED.index);  //颜色
                String value = getValue(list, obj, rules.get(j), i);
                String lowerValue = value.toLowerCase();
                XSSFRichTextString ts = new XSSFRichTextString(value); //单元格内容
                if (null != isHighLightKeyword && isHighLightKeyword && StringUtils.isNotEmpty(keyword)) {
                    //资质加红
                    if (rules.get(j).equalsIgnoreCase("certData")) {
                        List<String> keywordList = StringUtils.toListSpace(keyword);
                        for (String s : keywordList) {
                            if (s.length() > 6) {
                                List<Integer> allIndex = StringUtils.getAllIndex(lowerValue, s.toLowerCase());
                                if (!CollectionUtils.isEmpty(allIndex)) {
                                    for (Integer t : allIndex) {
                                        ts.applyFont(t, t + s.length(), font);
                                    }
                                }
                            }
                        }
                    }
                    if (CollectionUtils.isEmpty(keyStrSet)
                            || (keyStrSet.contains("projectName") && rules.get(j).equalsIgnoreCase("name"))
                            || (keyStrSet.contains("engineeringName") && rules.get(j).equalsIgnoreCase("engineeringName"))
                            || (keyStrSet.contains("licence") && rules.get(j).equalsIgnoreCase("licenceScale"))
                            || (keyStrSet.contains("contract") && rules.get(j).equalsIgnoreCase("contractScale"))
                            || (keyStrSet.contains("censor") && rules.get(j).equalsIgnoreCase("censorScale"))
                            || (keyStrSet.contains("project") && rules.get(j).equalsIgnoreCase("projectScale"))
                            || (keyStrSet.contains("completion") && rules.get(j).equalsIgnoreCase("completionScale"))
                            || (keyStrSet.contains("checkCompletion") && rules.get(j).equalsIgnoreCase("checkCompletionScale"))
                            || (keyStrSet.contains("completionMark") && rules.get(j).equalsIgnoreCase("completionMark"))
                            || (keyStrSet.contains("checkCompletionMark") && rules.get(j).equalsIgnoreCase("checkCompletionMark"))
                            || (keyStrSet.contains("tender") && rules.get(j).equalsIgnoreCase("tenderScale"))
                    ) {
                        List<String> keywordList = StringUtils.toListSpace(keyword);
                        for (String s : keywordList) {
                            List<Integer> allIndex = StringUtils.getAllIndex(lowerValue, s.toLowerCase());
                            if (!CollectionUtils.isEmpty(allIndex)) {
                                for (Integer t : allIndex) {
                                    ts.applyFont(t, t + s.length(), font);
                                }
                            }
                        }
                    }
                }
                if (!value.equals("-") && (rules.get(j).equalsIgnoreCase("licenceMoney") ||
                        rules.get(j).equalsIgnoreCase("contractMoney") ||
                        rules.get(j).equalsIgnoreCase("tenderMoney") ||
                        rules.get(j).equalsIgnoreCase("completionMoney"))) {
                    List<String> moenyList = Arrays.asList(value.split("\\|"));
                    for (String s : moenyList) {
                        int indexOf = lowerValue.indexOf(s.toLowerCase());
                        Double moeny = Double.valueOf(s);
                        if (indexOf >= 0 && moeny > 1000000) {
                            ts.applyFont(indexOf, indexOf + s.length(), font);
                        }
                    }
                }
                row.createCell(j).setCellValue(ts);
            }
        }
        if (merge) {
            for (Entry<String, Map<String, Integer>> data : rowValIndex.entrySet()) {
                int startRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(firstRowKey), 0).toString());
                int endRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(endRowKey), 0).toString());
                int startCell = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(firstCell)) {
                    startCell = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(firstCell), 0).toString());
                }
                int endCellIndex = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(endCell)) {
                    endCellIndex = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(endCell), 0).toString());
                }
                if (endRow < startRow) {
                    continue;
                }
//				log.info("key:"+data.getKey());
//				log.info("导出----》：startRow="+startRow+",endRow="+endRow+",startCell="+startCell+",endCellIndex="+endCellIndex);
                sheet.addMergedRegion(new CellRangeAddress(
                        startRow, //first row (0-based)
                        endRow, //last row  (0-based)
                        startCell, //first column (0-based)
                        endCellIndex  //last column  (0-based)
                ));
            }
        }
    }


    public static <T> void writeJCTSheet(List<T> list, XSSFSheet sheet, Integer startRowIndex, boolean merge, List<String> rules, Boolean isHighLightKeyword, Font font, String keyword, String serachScale) {
        String firstRowKey = "row_first";
        String endRowKey = "row_end";
        String firstCell = "cell_first";
        String endCell = "cell_end";
        Map<String, Map<String, Integer>> rowValIndex = new HashMap<String, Map<String, Integer>>();

        Map<String, Map<String, Integer>> cellValIndex = new HashMap<String, Map<String, Integer>>();
        for (int i = 0; i < list.size(); i++) {
            XSSFRow row = sheet.createRow(i + startRowIndex);
            T obj = list.get(i);
            for (int j = 0; j < rules.size(); j++) {
                String val = getValue(list, obj, rules.get(j), i);
                Map<String, Integer> rows = new HashMap<String, Integer>();
                rows.put(firstRowKey, i + startRowIndex);
                rowValIndex.put(val, rows);
                rowValIndex.get(val).put(endRowKey, i + startRowIndex);
                Map<String, Integer> cells = new HashMap<String, Integer>();
                cells.put(firstCell, j);
                cellValIndex.put(val, cells);
                cellValIndex.get(val).put(endCell, j);
                //关键词高亮
                font.setFontName("宋体"); // 字体
                font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);//粗体显示
                font.setColor(HSSFColor.RED.index);  //颜色
                String value = getValue(list, obj, rules.get(j), i);
                String lowerValue = value.toLowerCase();
                XSSFRichTextString ts = new XSSFRichTextString(value); //单元格内容
                if (null != isHighLightKeyword && isHighLightKeyword && StringUtils.isNotEmpty(keyword)) {
                    if (rules.get(j).equalsIgnoreCase("name")
                            || rules.get(j).equalsIgnoreCase("completionScale")
                            || rules.get(j).equalsIgnoreCase("licenceScale")
                            || rules.get(j).equalsIgnoreCase("contractScale")
                            || rules.get(j).equalsIgnoreCase("censorScale")
                            || rules.get(j).equalsIgnoreCase("projectScale")
                            || rules.get(j).equalsIgnoreCase("mark")
                            || rules.get(j).equalsIgnoreCase("tenderScale")
                    ) {
                        List<String> keywordList = StringUtils.toListSpace(keyword);
                        for (String s : keywordList) {
                            List<Integer> allIndex = StringUtils.getAllIndex(lowerValue, s.toLowerCase());
                            if (!CollectionUtils.isEmpty(allIndex)) {
                                for (Integer t : allIndex) {
                                    ts.applyFont(t, t + s.length(), font);
                                }
                            }
                        }
                    }
                }
                if (!value.equals("-") && (rules.get(j).equalsIgnoreCase("licenceMoney") ||
                        rules.get(j).equalsIgnoreCase("contractMoney") ||
                        rules.get(j).equalsIgnoreCase("tenderMoney") ||
                        rules.get(j).equalsIgnoreCase("completionMoney"))) {
                    List<String> moenyList = Arrays.asList(value.split("\\|"));
                    for (String s : moenyList) {
                        int indexOf = lowerValue.indexOf(s.toLowerCase());
                        Double moeny = Double.valueOf(s);
                        if (indexOf >= 0 && moeny > 1000000) {
                            ts.applyFont(indexOf, indexOf + s.length(), font);
                        }
                    }
                }
                row.createCell(j).setCellValue(ts);
            }
        }
        if (merge) {
            for (Entry<String, Map<String, Integer>> data : rowValIndex.entrySet()) {
                int startRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(firstRowKey), 0).toString());
                int endRow = Integer.parseInt(ObjectUtils.defaultIfNull(data.getValue().get(endRowKey), 0).toString());
                int startCell = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(firstCell)) {
                    startCell = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(firstCell), 0).toString());
                }
                int endCellIndex = 0;
                if (cellValIndex.containsKey(data.getKey()) && cellValIndex.get(data.getKey()).containsKey(endCell)) {
                    endCellIndex = Integer.parseInt(ObjectUtils.defaultIfNull(cellValIndex.get(data.getKey()).get(endCell), 0).toString());
                }
                if (endRow < startRow) {
                    continue;
                }
//				log.info("key:"+data.getKey());
//				log.info("导出----》：startRow="+startRow+",endRow="+endRow+",startCell="+startCell+",endCellIndex="+endCellIndex);
                sheet.addMergedRegion(new CellRangeAddress(
                        startRow, //first row (0-based)
                        endRow, //last row  (0-based)
                        startCell, //first column (0-based)
                        endCellIndex  //last column  (0-based)
                ));
            }
        }
    }

    public static <T> void writeSXSSFSheet(List<T> list, SXSSFSheet sheet, Integer startRowIndex, List<String> rules) {
        String firstRowKey = "row_first";
        String endRowKey = "row_end";
        String firstCell = "cell_first";
        String endCell = "cell_end";
        Map<String, Map<String, Integer>> rowValIndex = new HashMap<String, Map<String, Integer>>();
        Map<String, Map<String, Integer>> cellValIndex = new HashMap<String, Map<String, Integer>>();
        for (int i = 0; i < list.size(); i++) {
            Row row = sheet.createRow(i + startRowIndex);
            T obj = list.get(i);
            for (int j = 0; j < rules.size(); j++) {
                Cell cell = row.createCell(j);
                String val = getValue(list, obj, rules.get(j), i);
                Map<String, Integer> rows = new HashMap<String, Integer>();
                rows.put(firstRowKey, i + startRowIndex);
                rowValIndex.put(val, rows);
                rowValIndex.get(val).put(endRowKey, i + startRowIndex);
                Map<String, Integer> cells = new HashMap<String, Integer>();
                cells.put(firstCell, j);
                cellValIndex.put(val, cells);
                cellValIndex.get(val).put(endCell, j);
                String value = getValue(list, obj, rules.get(j), i);
                cell.setCellValue(value);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private static <T> String getValue(List<T> list, T obj, Object rule, int i) {
        String val;
        if (rule instanceof String) {
            try {
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(rule.toString(), obj.getClass());
                val = ObjectUtils.defaultIfNull(propertyDescriptor.getReadMethod().invoke(obj, new Object[]{}), "-").toString();
                if (StringUtils.isEmpty(val)) {
                    val = DEFAULT_VALUE;
                }
            } catch (Exception e) {
                log.error("generate - getVal", e);
                return "";
            }
        } else if (rule instanceof Function<?, ?>) {
            val = ((Function<T, String>) rule).apply(obj);
        } else if (rule instanceof RowConvert<?>) {
            val = ((RowConvert<T>) rule).convert(obj, i);
        } else if (rule instanceof ListConvert<?>) {
            val = ((ListConvert<T>) rule).convert(list, obj, i);
        } else {
            log.error("不能识别的转换器 !");
            return "";
        }
        return val;
    }

    public interface RowConvert<T> {

        String convert(T obj, int index);
    }

    public interface ListConvert<T> {

        String convert(List<T> list, T obj, int index);
    }

    public static void writeExcel(List<?> list, Sheet sheet, int lastRowNum, Object... rules)
            throws IOException, IllegalArgumentException,
            IllegalAccessException {

        Row row;
        for (int i = 0; i < list.size(); i++) {
            row = sheet.createRow((int) i + lastRowNum + 1);
            row.createCell(0).setCellValue(i + 1);
            Object tjb = list.get(i);
            Class class1 = (Class) tjb.getClass();
            Field[] fs = class1.getDeclaredFields();
            for (int j = 1; j < fs.length; j++) {
                for (int r = 0; r < rules.length; r++) {
                    if (rules[r].equals(fs[j].getName())) {
                        Field f = fs[j];
                        f.setAccessible(true);
                        Object v = f.get(tjb);
                        String type = f.getType().toString();
                        if (v == null || v.toString() == "") {
                            row.createCell(j).setCellValue("");
                        } else {

                            if (type.endsWith("Double") || type.endsWith("double")) {
                                row.createCell(j).setCellValue(
                                        Double.parseDouble(v.toString()));
                            } else if (type.endsWith("Integer") || type.endsWith("int")) {
                                row.createCell(j).setCellValue(
                                        Double.parseDouble(v.toString()));
                            } else if (type.endsWith("String")) {
                                row.createCell(j).setCellValue(v.toString());
                            }
                        }
                    }
                }
            }
        }
    }

}
